﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using GameSchoolApplication.Models;
using GameSchoolApplication.Models.ViewModels;

namespace GameSchoolApplication.Repositories
{

    public class AccountRepository
    {
        gsDBDataContext link = new gsDBDataContext();

        /// <summary>
        /// Gets UserAccount based on accountID
        /// Precondition: accountID must exist
        /// Postcondition: UserAccount has been returned
        /// Author: Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        /// <param name="accountID">ID of account to get.</param>
        public UserAccount getAccountByID(string accountID)
        {
            UserAccount selectedUser = (from u in link.UserAccounts
                               where u.userID == accountID
                               select u).First();
            return selectedUser; 
        }

        /// <summary>
        /// Gets UserAccount based on email
        /// Precondition: email must exist
        /// Postcondition: UserAccount has been returned
        /// Author: Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        /// <param name="accountEmail">E-mail address of account</param>
        public UserAccount getAccountByEmail(string accountEmail)
        {
            UserAccount user = (from u in link.UserAccounts
                               where u.email == accountEmail
                               select u).First();
            
            return user;
        }

        /// <summary>
        /// Checks if the user is a teacher
        /// Precondition: 
        /// Postcondition: 
        /// Author: Aron
        /// Date: 09.05.2012
        /// </summary>
        /// <param name="userID">userID</param>
        public bool isTeacher(string userID)
        {
            try
            {
                if ((from s in link.TeachesClasses
                         where s.teacherID == userID
                         select s).Count() > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Checks if the user is a teacher
        /// Precondition: 
        /// Postcondition: 
        /// Author: Aron
        /// Date: 09.05.2012
        /// </summary>
        /// <param name="userID">User ID</param>
        /// <param name="courseID">Course ID</param>
        public bool userTeachesCourse(string userID, int courseID)
        {
            try
            {
                if ((from s in link.TeachesClasses
                     where s.teacherID == userID && s.courseID == courseID
                     select s).Count() > 0)
                {
                    return true;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Returns a list of all UserAccounts
        /// Precondition:
        /// Postcondition: Userlist has been returned
        /// Author: Aron og Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        public IQueryable<UserAccount> getAllAccounts()
        {
            return link.UserAccounts;
        }

        /// <summary>
        /// Adds an account to the database.
        /// Precondition: 
        /// Postcondition: Account has been added to the database
        /// Author: Aron og Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        /// <param name="account">The account to add.</param>
        public bool addAccount(UserAccount account)
        {
            account.lastLogOn = DateTime.Now;
            try
            {
                link.UserAccounts.InsertOnSubmit(account);
                save(); 
            }
            catch (Exception)
            {
                return false;
            }
            return true; 
        }

        /// <summary>
        /// Deletes account from database with the specified ID.
        /// Precondition: ID must exist
        /// Postcondition: account has been removed from database
        /// Author: Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        /// <param name="accountID">ID of account to remove</param>
        public bool removeAccount(string accountID)
        {
            UserAccount user = (from u in link.UserAccounts
                               where u.userID == accountID
                               select u).First();
            if (user != null)
            {
                try
                {                    
                    link.UserAccounts.DeleteOnSubmit(user);
                }
                catch (Exception)
                {
                    return false;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Edits user information for a specific account.
        /// 
        /// Precondition: User must be an administrator and the account must exist
        /// Postcondition: Account information has been updated in the database
        /// Author: Aron Mar
        /// Date: 4.5.2012
        /// </summary>
        /// <param name="account">Contains the updated information of the account</param>
        public bool editAccount(UserAccount account)
        {
            try
            {
                var user = (from u in link.UserAccounts
                            where u.userID == account.userID
                            select u).First();
                
                user.userName = account.userName;
                user.sbux = account.sbux;
                user.passW = account.passW;
                user.name = account.name;
                user.isAdmin = account.isAdmin;
                user.email = account.email;
                
                save();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
            
        }

        /// <summary>
        /// Saves changes to database
        /// Precondition:
        /// Postcondition: Database has been updated
        /// Author: Aron og Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        public void save()
        {
            link.SubmitChanges();
        }

        /// <summary>
        /// Returns account with the specified userName
        /// Precondition: a user exists.
        /// Postcondition: An account has been returned
        /// Author: Aron og Bjarmi
        /// Date: 03.05.2012
        /// </summary>
        /// <param name="userName">Username of account to get.</param>
        public UserAccount getAccountByName(string userName)
        {
            var user = (from u in link.UserAccounts
                        where u.userName == userName
                        select u).First();
            return user;
        }

        public bool isAdmin(string userID)
        {
            var user = (from u in link.UserAccounts
                        where u.userID == userID
                        select u).First();
            return (user.isAdmin.HasValue ? user.isAdmin.Value : false);
        }
        /// <summary>
        /// Returns users points.
        ///  Author: Arnar
        ///  Date: 10.05.2012
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public UserInfo getPointsByUser(string userID)
        {
            var points = (from u in link.UserAccounts
                          where u.userID == userID
                          select new UserInfo 
                          { userID = u.userID, 
                            name = u.name, 
                            email = u.email, 
                            SBUX = u.sbux.Value, 
                            points = u.points.Value, 
                            lastOnline = u.lastLogOn.Value,
                            higher = getHigherPoints(userID)}).First();
            return (points);
        }
        /// <summary>
        /// Returns users points.
        ///  Author: Arnar
        ///  Date: 10.05.2012
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public int getHigherPoints(string userID)
        {
            var higher = (from u in link.UserAccounts
                          where u.points > (int)(from l in link.UserAccounts where l.userID == userID select l.points).First()
                          orderby u.points ascending
                          select u).Count();
            return (higher+1);
            
        }


        /// <summary>
        /// gets a username with his ID
        /// author:Bjarmi
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public string getUserNameByID(string userID)
        {
            var userName = (from u in link.UserAccounts
                            where u.userID == userID
                            select u.userName).First();
            return userName;
        }
        
        public bool isTeacherInCourse(string userID, int courseID)
        {
            var isTeacher = (from t in link.TeachesClasses
                     where t.teacherID == userID && t.courseID == courseID
                     select t).Count() > 0;
            return isTeacher; 
        }

        public int? getPointsAbove(string userID)
        {
            int? x = (from p in link.UserAccounts
                     where p.points > (from u in link.UserAccounts where u.userID == userID select u.points).First()
                     orderby p.points ascending
                     select p.points).First();

            return x;
        }

        public int? getPointsBelow(string userID)
        {
            int? x = (from p in link.UserAccounts
                      where p.points < (from u in link.UserAccounts where u.userID == userID select u.points).First()
                      orderby p.points descending
                      select p.points).First();

            return x;
        }
    }
}